/*
 * filename：SqlTemplateHandle.java
 * author： ewangshi
 * createDate：2013-07-18
 */
package com.ws.base.db.common;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import com.ws.base.exception.WSRuntimeException;

/**
 * @author ewangshi sql template handle "<[", "]>" PreparedStatement parameter
 *         only condition contains valid "<%", "%>" String parameter only
 *         condition contains valid
 */
public final class SqlTemplateHandle {

    private final static String[] F1 = { "<[", "]>" };
    private final static String[] F2 = { "<%", "%>" };

    private SqlTemplateHandle() {
    }

    private static class SingletonHolder {
        private final static SqlTemplateHandle INSTANCE = new SqlTemplateHandle();
    }

    public static SqlTemplateHandle getInstance() {
        return SingletonHolder.INSTANCE;
    }

    /**
     * execute enter
     * 
     * @param str
     *            sql
     * @param map
     *            condition
     * @return sql
     */
    public String execute(String str, Map<String, Object> map) {
        String temp = toSqlString(execute(str, map, F2));
        temp = toSqlString(execute(temp, map, F1));
        return temp;
    }

    private List<String> execute(String str, Map<String, Object> map, String[] f) {
        List<Map<String, Object>> list = new ArrayList<Map<String, Object>>();

        if (null != str && !"".equals(str)) {
            Map<String, Object> _map = new HashMap<String, Object>();
            int index = str.indexOf(f[0]);

            if (-1 == index) {
                _map.put("val", str);
            } else {
                _map.put("val", str.substring(0, index));
            }

            _map.put("flag", false);
            list.add(_map);
            handleSqlStr(index, str, list, f);
        }

        return argsHandle(map, f, list);
    }

    private void handleSqlStr(int index, String str,
            List<Map<String, Object>> list, String[] f) {
        int end = str.indexOf(f[1], index);
        Map<String, Object> _map = new HashMap<String, Object>();

        if (-1 == index) {
            return;
        }

        if (end == -1) {
            _map.put("val", str.substring(index));
            _map.put("flag", false);
        } else {
            _map.put("val", str.substring(index + f[1].length(), end));
            _map.put("flag", true);
        }
        list.add(_map);

        if (str.substring(end).length() - f[1].length() > 0) {
            int _index = str.indexOf(f[0], end);

            if (_index == -1) {
                Map<String, Object> _map2 = new HashMap<String, Object>();
                _map2.put("val", str.substring(end + f[1].length()));
                _map2.put("flag", false);
                list.add(_map2);
            } else {
                if (end + 1 < _index) {
                    Map<String, Object> _map2 = new HashMap<String, Object>();
                    _map2.put("val", str.substring(end + f[1].length(), _index));
                    _map2.put("flag", false);
                    list.add(_map2);
                }
                handleSqlStr(_index, str, list, f);
            }
        }
    }

    private List<String> argsHandle(Map<String, Object> map, String[] f,
            List<Map<String, Object>> list) {
        List<String> temps = new ArrayList<String>();

        for (Map<String, Object> m : list) {
            if (Boolean.parseBoolean(m.get("flag").toString())) {
                String str = m.get("val").toString();
                int index = str.indexOf(":");
                String temp = null;

                if (index != -1) {
                    int i = index;
                    for (; i < str.length(); i++) {
                        if (' ' == str.charAt(i) || ')' == str.charAt(i)
                                || '\'' == str.charAt(i)
                                || ',' == str.charAt(i) || '<' == str.charAt(i)) {
                            break;
                        }
                    }

                    temp = str.substring(index + 1, i);
                } else {
                    throw new WSRuntimeException("Not found \":\"");
                }

                if (null != temp) {
                    if (map.containsKey(temp) && null != map.get(temp)
                            && f == F1) {
                        temps.add(m.get("val").toString());
                    } else if (map.containsKey(temp) && null != map.get(temp)
                            && f == F2) {
                        temps.add(map.get(temp).toString());
                    }
                }
            } else {
                temps.add(m.get("val").toString());
            }
        }
        return temps;
    }

    private String toSqlString(List<String> strs) {
        StringBuffer buffer = new StringBuffer();

        for (String str : strs) {
            buffer.append(str);
        }

        return buffer.toString();
    }

    public static void main(String[] args) {
        String sql2 = "UPDATE T_APP_EXPENSE SET <[USERID = :userid,]> <[PRICE = :price,]> <[REMARK = :remark,]> <[CREATEDATE = :createDate,]> ID = :id WHERE ID = :id <%:zz%>";
        // String sql =
        // "SELECT ID, USERID, PRICE, REMARK, CREATEDATE, TYPE FROM T_APP_EXPENSE WHERE 1=1 <[ AND ID=:id  <%:zz%>]> <[AND USERID=:userid]> <%:orderStr%>";
        SqlTemplateHandle handle = new SqlTemplateHandle();
        Map<String, Object> map = new HashMap<String, Object>();
        map.put("userid", 1);
        map.put("id", 1);
        map.put("zz", 22);
        System.out.println(handle.execute(sql2, map));
    }
}
